//
//  NSArrayWXUtilsTest.m
//  WXUtils
//
//  Created by qianxia on 15/11/20.
//  Copyright © 2015年 黄旺鑫. All rights reserved.
//

#import <XCTest/XCTest.h>
#import "NSArray+WXUtils.h"

@interface NSArrayWXUtilsTest : XCTestCase

/// 测试数据
@property (strong, nonatomic) NSArray *subject;
@property (strong, nonatomic) NSArray *integers;
@property (strong, nonatomic) NSArray *floats;
@property (assign, nonatomic) NSInteger total;

@end

@implementation NSArrayWXUtilsTest

- (void)setUp {
    [super setUp];
    // Put setup code here. This method is called before the invocation of each test method in the class.
    
    self.subject = @[@"1", @"22", @"333"];
    self.integers = @[@(1), @(2), @(3)];
    self.floats = @[@(0.1), @(0.2), @(0.3)];
    self.total = 0;
}

- (void)tearDown {
    // Put teardown code here. This method is called after the invocation of each test method in the class.
    [super tearDown];
    
}

#pragma mark -

- (void)testEach {
    // 测试枚举
    void (^senderBlock)(NSString *) = ^(NSString *sender) {
        self.total += [sender length];
    };
    
    // 枚举
    [self.subject wx_each:senderBlock];
    
    // 枚举并并发执行代码块
    [self.subject wx_apply:^(NSString *obj) {
        NSLog(@"%@", obj);
        
    }];
    
    XCTAssertEqual(self.total, (NSInteger)6, @"total length of \"122333\" is %ld", (long)self.total);
}

- (void)testMatch {
    
    // 测试筛选
    BOOL (^validationBlock)(id) = ^(NSString *obj) {
        // 筛选出 @"22"
        self.total += [obj length];
        BOOL match = ([obj integerValue] == 22) ? YES : NO;
        return match;
    };
    
    // 执行筛选
    id found = [self.subject wx_match:validationBlock];
    
    XCTAssertEqual(self.total, (NSInteger)3, @"total length of \"122\" is %ld", (long)self.total);
    XCTAssertEqual(found, @"22", @"matched object is %@", found);
}

- (void)testNotMatch {
    
    // 测试筛选
    
    BOOL (^validationBlock)(id) = ^(NSString *obj) {
        self.total += [obj length];
        BOOL match = ([obj integerValue] == 4444) ? YES : NO;
        return match;
    };
    
    id found = [self.subject wx_match:validationBlock];
    
    // @return Returns the object if found, `nil` otherwise.
    XCTAssertEqual(_total, (NSInteger)6, @"total length of \"122333\" is %ld", (long)_total);
    XCTAssertNil(found, @"no matched object");
}

- (void)testSelect {
    
    // 测试筛选出符合条件的数组
    BOOL (^validationBlock)(id) = ^(NSString *obj) {
        self.total += [obj length];
        BOOL match = ([obj integerValue] < 300) ? YES : NO;
        return match;
    };
    
    NSArray *found = [self.subject wx_select:validationBlock];
    
    XCTAssertEqual(_total, (NSInteger)6, @"total length of \"122333\" is %ld", (long)_total);
    NSArray *target = @[@"1", @"22"];
    XCTAssertEqualObjects(found, target,  @"selected items are %@", found);
}

- (void)testSelectedNone {
    
    // 测试筛选出符合条件的对象数组
    BOOL (^validationBlock)(id) = ^(NSString *obj) {
        self.total += [obj length];
        BOOL match = ([obj integerValue] > 400) ? YES : NO;
        return match;
    };
    
    NSArray *found = [self.subject wx_select:validationBlock];
    
    XCTAssertEqual(_total, (NSInteger)6, @"total length of \"122333\" is %ld", (long)_total);
    XCTAssertTrue(found.count == 0, @"no item is selected");
}

- (void)testReject {
    
    // 筛选出不符合条件的对象数组
    BOOL (^validationBlock)(id) = ^(NSString *obj) {
        self.total += [obj length];
        BOOL match = ([obj integerValue] > 300) ? YES : NO;
        return match;
    };
    
    NSArray *left = [self.subject wx_reject:validationBlock];
    
    XCTAssertEqual(_total, (NSInteger)6, @"total length of \"122333\" is %ld", (long)_total);
    NSArray *target = @[@"1", @"22"];
    XCTAssertEqualObjects(left, target,  @"selected items are %@", left);
}

- (void)testRejectedAll {
    
    // 筛选出不符合条件的对象数组
    BOOL (^validationBlock)(id) = ^(NSString *obj) {
        self.total += [obj length];
        BOOL match = ([obj integerValue] < 400) ? YES : NO;
        return match;
    };
    
    NSArray *left = [self.subject wx_reject:validationBlock];
    
    XCTAssertEqual(_total, (NSInteger)6, @"total length of \"122333\" is %ld", (long)_total);
    
    XCTAssertTrue(left.count == 0, @"all items are rejected");
}

- (void)testMap {
    
    // 处理每个对象并生成一个处理过的数组
    id (^transformBlock)(id) = ^(NSString *obj) {
        self.total += [obj length];
        // 截取每个对象第一个字符串
        return [obj substringToIndex:1];
    };
    
    NSArray *transformed = [self.subject wx_map:transformBlock];
    
    XCTAssertEqual(_total, (NSInteger)6, @"total length of \"122333\" is %ld", (long)_total);
    
    NSArray *target = @[@"1", @"2", @"3"];
    XCTAssertEqualObjects(transformed, target, @"transformed items are %@", transformed);
}

- (void)testReduceWithBlock {
    
    // 遍历，生成一个结果 
    
    id (^accumlationBlock)(id, id) = ^(id sum, id obj) {
        return [sum stringByAppendingString:obj];
    };
    
    NSString *concatenated = [self.subject wx_reduce:@"" withBlock:accumlationBlock];
    
    XCTAssertTrue([concatenated isEqualToString:@"122333"], @"concatenated string is %@", concatenated);
}

- (void)testReduceWithBlockInteger {
    
    // 数组累加
    NSInteger (^accumlationBlockInteger)(NSInteger, id) = ^(NSInteger result, id obj) {
        return result + [obj integerValue];
    };
    
    NSInteger result = [self.integers wx_reduceInteger:0 withBlock:accumlationBlockInteger];
    XCTAssertEqual(result, 6, @"reduce int result is %ld", (long)result);
}

- (void)testReduceWithBlockCGFloat {
    
    CGFloat (^accumlationBlockFloat)(CGFloat, id) = ^CGFloat(CGFloat result, id obj) {
#if __LP64__
        return result + [obj doubleValue];
#else
        return result + [obj floatValue];
#endif
    };
    
    CGFloat result = [self.floats wx_reduceFloat:0.0 withBlock:accumlationBlockFloat];
#if __LP64__
    CGFloat accuract = DBL_EPSILON;
#else
    CGFloat accuract = FLT_EPSILON;
#endif
    
    XCTAssertEqualWithAccuracy(result, (CGFloat)0.6, accuract, @"reduce float result is %f", result);
}

- (void)testAny {
    
    // 判断是否存在符合代码块条件的对象
    
    // 检查数组是否存在开头为1
    BOOL (^existsBlockTrue)(id) = ^(id obj) {
        return [obj hasPrefix:@"1"];
    };
    
    BOOL (^existsBlockFalse)(id) = ^(id obj) {
        return [obj hasPrefix:@"4"];
    };
    
    BOOL letterExitst = [self.subject wx_any:existsBlockTrue];
    XCTAssertTrue(letterExitst, @"letter is not in array");
    
    BOOL letterDoesNotExist = [self.subject wx_any:existsBlockFalse];
    XCTAssertFalse(letterDoesNotExist, @"letter is in array");
}

- (void)testAll {
    NSArray *names = @[@"John", @"Joe", @"Jon", @"Jester"];
    NSArray *names2 = @[@"John", @"Joe", @"Jon", @"Mary"];
    
    BOOL (^nameStartsWithJ)(id) = ^(id obj) {
        return [obj hasPrefix:@"J"];
    };
    
    BOOL allNamesStartWithJ = [names wx_all:nameStartsWithJ];
    XCTAssertTrue(allNamesStartWithJ, @"all names do not start with J in array");
    
    BOOL allnamesDoNotStartWithJ = [names2 wx_all:nameStartsWithJ];
    XCTAssertFalse(allnamesDoNotStartWithJ, @"all names do start with J in array");
}

- (void)testNone {
    // 没有一个对象符合代码块条件
    NSArray *names = @[@"John", @"Joe", @"Jon", @"Jester"];
    NSArray *names2 = @[@"John", @"Joe", @"Jon", @"Mary"];
    
    BOOL (^nameStartsWithM)(id) = ^(id obj) {
        return [obj hasPrefix:@"M"];
    };
    
    BOOL noNamesStartWithM = [names wx_none:nameStartsWithM];
    XCTAssertTrue(noNamesStartWithM, @"some names start with M in array");
    
    BOOL someNamesStartWithM = [names2 wx_none:nameStartsWithM];
    XCTAssertFalse(someNamesStartWithM, @"no names start with M in array");
}

- (void)testCorresponds {
    
    // 判断两个数组是否对于符合代码块条件
    NSArray *numbers = @[ @(1), @(2), @(3) ];
    NSArray *letters = @[ @"1", @"2", @"3" ];
    
    BOOL doesCorrespond = [numbers wx_corresponds:letters withBlock:^BOOL(id number, id letter) {
        return [[number stringValue] isEqualToString:letter];
    }];
    
    XCTAssertTrue(doesCorrespond, @"1,2,3 does not correspond to \"1\",\"2\",\"3\"");
}

- (void)testJSONString {
    // 数组转化为JSON字符串
    NSArray *array = @[@"Object 1", @{@"Dict Key": @43}];
    NSString *JSONString = array.JSONString;
    
    XCTAssertEqualObjects(JSONString, @"[\"Object 1\",{\"Dict Key\":43}]");
}

- (void)testDistinctArray {
    
    // 测试移除重复的对象
    NSArray *subject = @[@"6", @"1", @"2", @"2", @"2", @"2", @"3", @"2", @"22", @"1", @"5"];
    NSArray *uniqueAry = subject.distinctArray;
    XCTAssertEqual(uniqueAry.count, 6,  @"Unique array should have a count of 6.");
    
}

- (void)testRemoveNull {
    // 测试移除null对象
    NSNull *null = [NSNull null];
    NSArray *subject = @[@"1", @{@"ab": null, @"abc": null, @"abd": null, @"abe": null, @"abcf": null, @"abg": null, @"abh": null}, null, null, null, null, null, @"2", @"3", @[@"25", null, null, null, null, null, null, @"5"], @[null], null, @"2"];
    
    NSArray *result = [subject removeNulls];
    
    NSString *JSONString = result.JSONString;
    NSLog(@"%@", JSONString);
    XCTAssertTrue(![JSONString containsString:@"null"]);
}

- (void)testUnionWithArray{
    
    // 测试
    NSArray *subject = @[@"6", @"1", @"2", @"2", @"2", @"2", @"3", @"2", @"22", @"1", @"5"];
    NSArray *otherAry = @[@"1", @"2", @"7", @"9", @"10", @"11", @"19", @"22"];
    NSArray *unionAry = [subject wx_unionWithArray:otherAry];
    
    NSLog(@"%@", unionAry.JSONString);
    
    NSArray *target = @[@"6", @"1", @"2", @"3", @"22", @"5", @"7", @"9", @"10", @"11", @"19"];
    XCTAssertEqualObjects(unionAry, target, @"两个数组必须相同");
}

- (void)testIntersectionWithArray {
    // 找出两个数组都出现的对象
    NSArray *subject = @[@"6", @"6", @"1", @"2", @"2", @"2", @"2", @"3", @"2", @"22", @"1", @"5"];
    NSArray *otherAry = @[@"1", @"2", @"7", @"9", @"10", @"11", @"19", @"22"];
    NSArray *unionAry = [subject wx_intersectionWithArray:otherAry];
    
    NSLog(@"%@", unionAry.JSONString);
    NSArray *target = @[@"1", @"2", @"22"];
    XCTAssertEqualObjects(unionAry, target, @"两个数组必须相同");
}

- (void)testDifferenceToArray {
    // 找出没有在otherAry出现的对象
    NSArray *subject = @[@"6", @"6", @"1", @"2", @"2", @"2", @"2", @"3", @"2", @"22", @"1", @"5"];
    NSArray *otherAry = @[@"1", @"2", @"7", @"9", @"10", @"11", @"19", @"22"];
    NSArray *unionAry = [subject wx_differenceToArray:otherAry];
    
    NSLog(@"%@", unionAry.JSONString);
    NSArray *target = @[@"6", @"3", @"5"];
    XCTAssertEqualObjects(unionAry, target, @"两个数组必须相同");
}

@end
